package com.yunzai.secure.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.yunzai.generic.service.IRedisService;
import com.yunzai.secure.domain.LoginUser;
import com.yunzai.secure.service.ITokenService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class TokenServiceImpl implements ITokenService {

    @Value("${token.secret}")
    private String secret;

    @Value("${token.expireTime}")
    private int expireTime;

    @Value("${token.authorization}")
    private String authorization;

    @Autowired
    private IRedisService redisService;

    @Override
    public String create(Authentication authentication) {
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String token = JWT.create()
                .withClaim("uuid", uuid)
                .sign(Algorithm.HMAC256(secret));
        redisService.setValue("yunzai_api_login_token:" + uuid, (LoginUser) authentication.getPrincipal(), expireTime, TimeUnit.MINUTES);
        return token;
    }

    @Override
    public void update(HttpServletRequest request, LoginUser loginUser) {
        String attribute = request.getHeader(authorization);
        String token = attribute.substring("Bearer ".length(), attribute.length() - 1);
        String uuid = getUUID(token);
        redisService.setValue("yunzai_api_login_token:" + uuid, loginUser, expireTime, TimeUnit.MINUTES);
    }

    @Override
    public String delete(String token) {
        DecodedJWT jwt = JWT.decode(token);
        redisService.deleteValue("yunzai_api_login_token:" + jwt.getClaim("uuid").asString());
        return token;
    }

    @Override
    public Authentication getAuthentication(String token) {
        DecodedJWT jwt = JWT.decode(token);
        String uuid = jwt.getClaim("uuid").asString();
        if (isValid(uuid)) {
            JSONObject obj = redisService.getValue("yunzai_api_login_token:" + uuid);
            if (obj == null) return null;
            LoginUser value = obj.toJavaObject(LoginUser.class);
            redisService.setValue("yunzai_api_login_token:" + uuid, value, expireTime, TimeUnit.MINUTES);
            return new UsernamePasswordAuthenticationToken(value, value.getPassword(), value.getAuthorities());
        } else {
            return null;
        }
    }

    @Override
    public LoginUser getLoginUser(String token) {
        DecodedJWT jwt = JWT.decode(token);
        String uuid = jwt.getClaim("uuid").asString();
        if (isValid(uuid)) {
            JSONObject obj = redisService.getValue("yunzai_api_login_token:" + uuid);
            return obj.toJavaObject(LoginUser.class);
        } else {
            return null;
        }
    }

    @Override
    public String getUUID(String token) {
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getClaim("uuid").asString();
    }

    // 使令牌失效（加入黑名单）
    @Override
    public void invalidate(String token) {
        DecodedJWT jwt = JWT.decode(token);
        // 1小时后自动移除
        Long time = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1);
        redisService.setValue("yunzai_api_login_blacklist:" + jwt.getClaim("uuid").asString(), time, 1, TimeUnit.HOURS);
    }

    // 验证令牌有效性
    private boolean isValid(String uuid) {
        Long expireTime = redisService.getValue("yunzai_api_login_blacklist:" + uuid);
        if (expireTime == null) {
            return true; // 不在黑名单中，有效
        }
        return System.currentTimeMillis() > expireTime; // 已过期则从黑名单移除
    }

}
